package zdream.control.foe.mm;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;

import zdream.control.world.*;
import zdream.control.region.Terrains;
import zdream.utils.math.MathUtils;

import static zdream.control.world.Box.pToBlock;
import static zdream.control.world.MFoe.PATTERN_NORMAL;
import static zdream.control.region.TerrainConstant.*;
import static zdream.control.world.MFoeConstants.CATEGORY_MOTION;
import static zdream.control.world.MFoeConstants.TAG_CLIMBING;

/**
 * @author Zdream
 * @since 0.0.1
 * @date 2022-05-28
 */
public class MegaManMotionModule extends MFoeBuff {
	final MegaMan mm;

	public MegaManMotionModule(MegaMan mm) {
		super(mm);
		this.mm = mm;
	}

	@Override
	public String getCategory() {
		return CATEGORY_MOTION;
	}

	@Override
	public void init() {
		this.pDeltaVx = MegaManConstant.MEGAMAN_HORIZONTAL_VELOCITY_DELTA;
		this.pMaxVx = MegaManConstant.MEGAMAN_HORIZONTAL_VELOCITY_MAX;
		this.pParryVx = MegaManConstant.MEGAMAN_PARRY_VELOCITY;

		this.onIce = false;

		mm.terrainHandler = new TerrainHandler(mm.world);
		mm.terrainHandler.climbable = true;
		mm.terrainHandler.xOutsideTerrain = TERRAIN_SOLID;

		mm.gravityVelocity = -28;

		onHook(MHookType.RECEIVE_DAMAGE)
				.withPriority(15)
				.handle(this::afterReceiveDamage)
				.buildAndSave();
		onHook(MHookType.TICK)
				.withPriority(-15)
				.handle(this::tick)
				.buildAndSave();
	}

	public void tick(MHooks.MHookContext rawContext) {
		Ticker ticker = foe.world.ticker;
		prepare();

		// 处理 glitch
		TerrainHandler tHandler = mm.terrainHandler;
		boolean success = tHandler.glitchFix(mm);
		if (!success) {
			System.err.println("穿墙啦");
		}

		// 查询洛克人状态, 含:
		// box 初始化、在地形中的情形、是否受伤僵直、移动情况
		tHandler.freshBox(mm);
		if (checkDropOutside()) {
			return;
		}

		motionEnable = true;
		emitBeforeMotionEvent();

		handleImmune(ticker);
		handleClimb(ticker);
		handleMotion(ticker);

		// 处理攻击情况 + 使用道具情况
		mm.weaponModule.handleFire(ticker);
		mm.weaponModule.handleProp(ticker);

		// 最后……
		// 处理左右移动
		submitMotion();
		tHandler.freshBox(mm);
	}

	public void submitMotion() {
		mm.terrainHandler.submitMotion(mm);
	}

	public void submitMotion(float deltaX, float deltaY) {
		mm.terrainHandler.submitMotion(mm, deltaX, deltaY);
	}

	private void prepare() {
		mm.velocityX = 0;
		mm.velocityY = 0;

		mm.flush();
	}

	private final List<Consumer<MFoe>> beforeMoveExtensions = new ArrayList<>();

	private void emitBeforeMotionEvent() {
		if (beforeMoveExtensions.isEmpty()) {
			return;
		}
		for (Consumer<MFoe> extension : beforeMoveExtensions) {
			extension.accept(mm);
		}
	}

	/**
	 * 添加 beforeMoveExtension, 返回是删除添加的 beforeMoveExtension 的方法
	 */
	public BooleanSupplier addBeforeMoveExtension(Consumer<MFoe> checker) {
		this.beforeMoveExtensions.add(checker);
		return () -> this.beforeMoveExtensions.remove(checker);
	}

	private void afterReceiveDamage(MHooks.MHookContext rawContext) {
		final MHooks.DamageContext context = rawContext.as();
		if (!context.accepted) {
			return;
		}

		int damage = context.damage;
		if (damage != 0) {
			stiffness = 450;
		}

		climbing = NO_CLIMBING;
		removeTag(TAG_CLIMBING);

		if (slideDuration == -1 || slideDuration > 0 && canSlideReset()) {
			slideDuration = -1;
			mm.applyPattern(PATTERN_NORMAL);
		} else {
			slideDuration = MAX_SLIDE_DURATION;
		}
	}

	/* **********
	 * 横向移动 *
	 ********** */

	/*
	 * 原配置值
	 */
	/**
	 * 水平速度最大值
	 */
	public float pMaxVx = MegaManConstant.MEGAMAN_HORIZONTAL_VELOCITY_MAX;
	/**
	 * 水平加速时的速度 (不在冰面上)
	 */
	public float pDeltaVx = MegaManConstant.MEGAMAN_HORIZONTAL_VELOCITY_DELTA;
	/**
	 * 击退时的速度, 单位: p/s
	 */
	public float pParryVx = MegaManConstant.MEGAMAN_PARRY_VELOCITY;

	/*
	 * 移动参数 (当前值)
	 */
	/**
	 * 是否处理左右移动的 motion.
	 * 当洛克站在 RushJet 上, 这个值为 false
	 */
	public boolean motionEnable = false;
	/**
	 * 上一次计算的横坐标速度, 仅计算走路导致的横坐标
	 */
	public float pLastVx; // horizontalVelDelta
	/**
	 * 本次计算的横坐标速度, 仅计算走路导致的横坐标
	 */
	public float pCurVx; // horizontalVelDelta
	/**
	 * 当前值
	 */
	public float deltaX;
	/**
	 * 是否在冰面上, 或者类似冰面的效果
	 */
	public boolean onIce;
	/**
	 * 是否在行走. 向右行走:1, 左:-1, 无:0
	 */
	public byte walking;

	/*
	 * 滑铲参数
	 */
	/**
	 * 滑铲速度是水平方向. 滑铲一旦触发, 如果不取消则默认持续 0.6 秒时间.
	 * 速度 8.33 p/s
	 */
	public float slideVx = 8.33f;
	/**
	 * 滑铲的时长. 单位毫秒
	 * 值域: -1 & [0, MAX_SLIDE_DURATION]. -1 表示没有滑铲, 大于等于 0 表示滑铲中.
	 * 滑铲第一帧为 0, 到 MAX_SLIDE_DURATION 时就不再加, 滑铲结束后为 -1.
	 */
	public long slideDuration = -1;
	public static final long MAX_SLIDE_DURATION = 500;

	/*
	 * 攀爬参数
	 */
	/**
	 * 攀爬速度, 每秒攀爬的格子数. 配置项
	 * 单位: p/s, 默认 5 p/s
	 * climbVelocity
	 */
	float climbVy = 5;
	/**
	 * 攀爬状态参数,
	 * -1 表示不攀爬,
	 * 0 表示攀爬中,
	 * [1-100] 表示在梯子顶端的特殊攀爬状态,
	 * 共 100 毫秒时间 (0.1 s)
	 *
	 * 如果上一帧不为 0, 后面每帧都需要检测, 直到将其设置为 0
	 */
	public byte climbing = NO_CLIMBING;
	public static final byte NO_CLIMBING = -1;
	public static final byte CLIMBING = 0;
	public static final byte CLIMBING_TOP = 100;
	/**
	 * 当前帧攀爬的方向, 0: 无, 1: 上, -1: 下,
	 * 每帧不重置 / upOrDown
	 */
	public byte climbDirection;
	/**
	 * 由于在攀爬状态下攻击将有 0.25 秒时间不能上下移动, 这里记录剩余的恢复速度
	 * [1 ~ 250]
	 */
	public long climbHaltRemain;

	/**
	 * 受伤硬直剩余时间, [0, 450]
	 */
	public long stiffness = 0;

	private boolean checkDropOutside() {
		boolean dropOutside = mm.world.dropOutside(mm);
		if (dropOutside) {
			mm.destroy(MFoe.DestroyCause.OUTSIDE);
			return true;
		}

		return false;
	}

	private void handleImmune(Ticker ticker) {
		if (stiffness > 0) {
			stiffness = Math.max(0, stiffness - ticker.lDuration);
		}

		// debug
//		final HealthModule module = mm.healthModule;
//		if (module.immuneRemain == 0) {
//			if (module.hp < module.hpMax) {
//				module.hp += (ticker.lDuration / 4);
//			}
//		}
	}

	/**
	 * 进入攀爬状态
	 */
	private void setClimb(byte climbing) {
		if (climbing == CLIMBING) {
			mm.applyPattern(PATTERN_NORMAL);
		} else if (climbing == NO_CLIMBING || climbing > 100) {
			this.climbing = NO_CLIMBING;
			this.climbDirection = 0;
			removeTag(TAG_CLIMBING);
			mm.applyPattern(PATTERN_NORMAL);
			return;
		} else if (climbing > 50) {
			mm.applyPattern(MegaMan.PATTERN_CLIMB_TOP_1);
		} else {
			mm.applyPattern(MegaMan.PATTERN_CLIMB_TOP_0);
		}

		this.climbing = climbing;
		addTag(TAG_CLIMBING);
		this.slideDuration = -1;
		mm.jumpModule.resetJumpVel();
	}

	private void handleClimb(Ticker ticker) {
		Box box = mm;
		TerrainHandler tHandler = mm.terrainHandler;
		final float pCenterX = box.getCenterX();
		final float pCenterY = box.getCenterY();
		final int centerX = pToBlock(pCenterX);
		final int centerY = pToBlock(pCenterY);
		int lDuration = (int) ticker.lDuration;
		// 现在查看这个中心点映射到的是哪个地形

		// 表示当前帧, 角色从未攀爬的状态变成附到梯子上
		boolean adhere = false;

		// 表示在梯子顶端按下将下降到下面的梯子上
		int lowerX = -1, lowerY = -1; // 单位: 块

		boolean up = mm.controlModule.up;
		boolean down = mm.controlModule.down;

		// 开始是 normal 状态, 看能不能附上梯子
		NORMAL_TO_CLIMBING:
		if (climbing == NO_CLIMBING && stiffness == 0) {
			climbHaltRemain = 0;
			if (!up && !down) {
				break NORMAL_TO_CLIMBING;
			}

			byte terrain = tHandler.getTerrain(centerX, centerY);
			if (Terrains.isLadder(terrain)) {
				// 这个时候如果按了上或者下, 就应该到梯子上了, 除了一种情况: 你在落地时按下
				// TODO (没测落地时按下)
				int byBottom = pToBlock(box.pos.y);
				float pyTop = box.pos.y + box.pos.height;
				int byTop = pToBlock(pyTop);

				if (box.gravityDown && byBottom == box.pos.y) {
					if (tHandler.getTerrain(centerX, byBottom - 1) == TERRAIN_SOLID && down) {
						// do-nothing
					} else {
						adhere = true;
					}
				} else if (!box.gravityDown && pyTop == byTop) {
					if (tHandler.getTerrain(centerX, byTop + 1) == TERRAIN_SOLID && up) {
						// do-nothing
					} else {
						adhere = true;
					}
				} else {
					adhere = true;
				}
			} else {
				// 还有一种情况, 在梯子顶端按下将下降到下面的梯子上
				if (up && box.gravityDown || down && !box.gravityDown) {
					break NORMAL_TO_CLIMBING;
				}
				int byBottom = pToBlock(box.pos.y);
				float pyTop = box.pos.y + box.pos.height;
				int byTop = pToBlock(pyTop);

				if (box.gravityDown && byBottom == box.pos.y) {
					if (Terrains.isLadder(tHandler.getTerrain(centerX, byBottom - 1))) {
						// 可以向下降到梯子上
						// lower is true;
						lowerX = centerX;
						lowerY = byBottom;
					}
				} else if (!box.gravityDown && pyTop == byTop) {
					if (Terrains.isLadder(tHandler.getTerrain(centerX, byTop + 1))) {
						// 人是倒着的, 可以向上“降”到梯子上
						// lower is true;
						lowerX = centerX;
						lowerY = byTop;
					}
				}
			}
		}

		if (climbing == NO_CLIMBING) {
			if (adhere) {
				box.setAnchorX(pToBlock(pCenterX) + 0.5f);
				box.setVelocity(0, 0);
				setClimb(CLIMBING);
			} else if (lowerX != -1) {
				box.setAnchorX(lowerX + 0.5f);
				box.setAnchorY(lowerY);
				box.setVelocity(0, 0);
				setClimb(CLIMBING_TOP);
			}
			// 刚附上去的第一帧不判定上下移动
			return;
		}

		// 以下的 climbing 都是 >= 0 的
		mm.jumpModule.resetJumpVel();
		if (!mm.controlModule.lastJump && mm.controlModule.jump) {
			setClimb(NO_CLIMBING);
			return;
		}

		// 处理 climbHaltRemain
		if (climbHaltRemain > 0) {
			climbHaltRemain = Math.max(0, climbHaltRemain - ticker.lDuration);
		}

		if (climbHaltRemain == 0) {
			if (mm.controlModule.left) {
				box.orientation = false;
			} else if (mm.controlModule.right) {
				box.orientation = true;
			}
		}

		this.climbDirection = (byte) (up ? 1 : down ? -1 : 0);
		if (this.climbDirection == 0) {
			return;
		}

		// 阶段 2: climbing  <->  特殊攀爬状态
		// 特殊攀爬状态
		// climbing 在 [1,50]   y = 顶-0.25
		// climbing 在 [51,100]   y = 顶
		STEP2: {
			if (climbing >= 1) {
				int last = climbing;
				box.setVelocity(0, 0);

				int delta = (byte) ((up ^ box.gravityDown) ? -lDuration : lDuration);
				setClimb((byte) MathUtils.clamp(climbing + delta, 0, 101));

				if (climbing == NO_CLIMBING) {
					// 站在楼梯顶端, 100 -> -1
				} else if (climbing == CLIMBING) {
					// 回到一般状态
					box.setAnchorY(MathUtils.ceilPositive(box.anchorY) - 0.55f);
				} else if (last <= 50 && climbing >= 51) {
					box.setAnchorY(MathUtils.ceilPositive(box.anchorY));
				} else if (last >= 51 && climbing <= 50) {
					box.setAnchorY(MathUtils.ceilPositive(box.anchorY) - 0.25f);
				}

				break STEP2;
			}

			// 角色将改变形状 (共 3 个形状, 存储在 StateModule 中的 motion 字段)、
			// 姿势 (爬梯子状态, Box 里面的参数)

			// 角色如果原本不在爬梯子状态, 需要对角色的位置进行调整,
			// 平移到梯子上;
			box.setAnchorX(pToBlock(pCenterX) + 0.5f);

			// 将根据角色与梯子顶端的距离来设置爬梯子状态;

			// 下面需要粗略计算离梯子顶端的距离 (这里的 y 以角色锚点为准)
			float distance;
			int ladderTopY;
			if (box.gravityDown) {
				ladderTopY = MathUtils.ceilPositive(box.anchorY);
				distance = ladderTopY - box.anchorY;
				if (distance < 0.5f && Terrains.isLadder(tHandler.getTerrain(centerX, ladderTopY))) {
					distance ++;
					ladderTopY ++;
				}
			} else {
				ladderTopY = MathUtils.floorPositive(box.anchorY);
				distance = box.anchorY - ladderTopY;
				if (distance < 0.5f && Terrains.isLadder(tHandler.getTerrain(centerX, ladderTopY - 1))) {
					distance ++;
					ladderTopY --;
				}
			}
			float deltaY = 0;

			// deltaY
			if (distance < 0.5f) {
				// 两个快爬到顶端的状态, 速度和状态需要修改
				setClimb((byte) Math.min(1 + lDuration, 50));
				box.setAnchorY(box.gravityDown ? ladderTopY - 0.25f : ladderTopY + 0.25f);
			} else {
				// 离顶端还很远
				// 当在攻击状态时, 将不移动
				if (climbHaltRemain == 0) {
					if (up) {
						deltaY = climbVy * ticker.duration;
					} else { // down
						deltaY = -climbVy * ticker.duration;
					}
				}
			}

			// 如果在底端按下, 也会退出攀爬状态
			if (climbing == CLIMBING) {
				if (box.gravityDown && box.bottomTouched && down &&
				tHandler.getTerrain(centerX, pToBlock(box.pos.y) - 1) == TERRAIN_SOLID
						|| !box.gravityDown && box.topTouched && up &&
				tHandler.getTerrain(centerX, pToBlock(box.pos.y + box.pos.height) + 1) == TERRAIN_SOLID) {
					setClimb(NO_CLIMBING);
					mm.applyPattern(PATTERN_NORMAL);
				}
			}

			box.setVelocityX(0);
			box.setVelocityY(deltaY);
		}
	}

	private void handleMotion(Ticker ticker) {
		pLastVx = pCurVx;
		pCurVx = 0;
		deltaX = 0;

		// 4. 跳跃 / 滑铲判定
		Box box = mm;
		TerrainHandler tHandler = mm.terrainHandler;
		boolean lastSlide = mm.controlModule.lastSlide;
		boolean slide = mm.controlModule.slide;
		boolean jump = mm.controlModule.jump;
		boolean lastJump = mm.controlModule.lastJump;
		boolean down = mm.controlModule.down;
		boolean inAir = box.inAir;
		boolean jumpStart = false;
		boolean jumpEnd = false;

		boolean startSlide = !lastSlide && slide && slideDuration == -1 && !inAir && climbing == NO_CLIMBING;
		if (jump && !lastJump && down) {
			// 判断成滑铲
			startSlide = slideDuration == -1 && !inAir && climbing == NO_CLIMBING;
		} else {
			jumpStart = !lastJump && jump && stiffness == 0 && !inAir;
			jumpEnd = (lastJump && !jump) || stiffness > 0 && inAir;

			// 攀爬中起跳问题
			if (climbing == 1) { // 不会僵直
				if (!lastJump && jump) {
					setClimb(NO_CLIMBING);
				}
			} else if (climbing > 1) { // 不会僵直
				jumpStart = !lastJump && jump;
				if (jumpStart) {
					setClimb(NO_CLIMBING);
					box.setAnchorY(MathUtils.ceilPositive(box.anchorY));
					tHandler.freshBox(box);
					inAir = box.inAir;
				}
			}

			// 滑铲中起跳问题
			if (jumpStart && slideDuration > 0) {
				if (!canSlideReset()) {
					jumpStart = false;
				}
			}
		}

		if (jumpStart) {
			mm.jumpModule.jump();
		} else if (jumpEnd) {
			mm.jumpModule.releaseJump();
		}

		// 5. 执行左右移动
		if (!motionEnable) {
			mm.applyPattern(PATTERN_NORMAL);
		} else if (stiffness != 0)  STIFFNESS: {
			// 如果滑铲状态还在 (受伤时滑铲无法取消的情况)
			if (slideDuration > 0) {
				if (canSlideReset()) {
					slideDuration = -1;
					mm.applyPattern(PATTERN_NORMAL);
				} else {
					break STIFFNESS; // vx is 0
				}
			} else {
				if (climbing != NO_CLIMBING) {
					setClimb(NO_CLIMBING);
				}
				mm.applyPattern(PATTERN_NORMAL);
			}
			walking = 0;
		} else {
			// 处理滑铲
			if (startSlide) {
				// 开始滑铲时要判断是否有空间. 没空间的话, 调用该方法也不会启动滑铲
				trySlideStart();
			} else if (this.slideDuration >= 0) {
				if (this.slideDuration >= MAX_SLIDE_DURATION || inAir ||
						((box.orientation && box.rightTouched || !box.orientation && box.leftTouched)) && this.slideDuration >= 100) {
					if (canSlideReset()) {
						mm.applyPattern(PATTERN_NORMAL);
						this.slideDuration = -1;
					}
				} else {
					this.slideDuration = Math.min(MAX_SLIDE_DURATION, this.slideDuration + ticker.lDuration);
				}
			}
		}

		boolean left = mm.controlModule.left;
		boolean right = mm.controlModule.right;
		if (!motionEnable) {
			if (left) {
				box.orientation = false;
			} else if (right) {
				box.orientation = true;
			}
			pCurVx = 0;
			walking = 0;
		} else if (stiffness > 0) {
			if (onIce) { // 在击退 / 硬直状态下
				if (box.orientation) {
					calcVelocity(pCurVx, -pDeltaVx, -pParryVx, ticker);
				} else {
					calcVelocity(pCurVx, pDeltaVx, pParryVx, ticker);
				}
			} else {
				pCurVx = box.orientation ? -pParryVx : pParryVx;
				deltaX = pCurVx * ticker.duration;
			}
		} else if (climbing >= 0) {
			walking = 0;
			pCurVx = 0;
		} else if (left) {
			walking = -1;
			box.orientation = false;
			if (inAir) { // 空中
				pCurVx = -pMaxVx;
				deltaX = -pMaxVx * ticker.duration;
			} else if (slideDuration >= 0) {
				pCurVx = -slideVx;
				deltaX = pCurVx * ticker.duration;
			} else { // 落地, 向左走
				if (pLastVx > 0 && !onIce/* || box.leftTouched*/) { // 上一帧方向朝右
					pCurVx = 0;
				} else { // TODO 不考虑冰面
					calcVelocity(pLastVx, -pDeltaVx, -pMaxVx, ticker);
					if (pCurVx > 0) {
						System.err.println("error");
					}
				}
			}
		} else if (right) {
			walking = 1;
			box.orientation = true;
			if (inAir) { // 空中
				pCurVx = pMaxVx;
				deltaX = pMaxVx * ticker.duration;
			} else if (slideDuration >= 0) {
				pCurVx = slideVx;
				deltaX = pCurVx * ticker.duration;
			} else { // 落地, 向右走
				if (pLastVx < 0 && !onIce /*|| box.rightTouched*/) { // 上一帧方向朝左
					pCurVx = 0;
				} else { // TODO 不考虑冰面
					calcVelocity(pLastVx, pDeltaVx, pMaxVx, ticker);
					if (pCurVx < 0) {
						System.err.println("error");
					}
				}
			}
		} else {
			walking = 0;
			if (slideDuration >= 0) {
				pCurVx = (box.orientation) ? slideVx : -slideVx;
				deltaX = pCurVx * ticker.duration;
			} else if (!onIce) {
				pCurVx = 0; // 不在打滑状态下, 立即停住
				deltaX = 0;
			} else {
				if (pLastVx > 0) {
					calcVelocity(pLastVx, -pDeltaVx, 0, ticker);
				} else if (pLastVx < 0) {
					calcVelocity(pLastVx, pDeltaVx, 0, ticker);
				} else {
					pCurVx = 0;
				}
			}
		}

		box.velocityX += deltaX;

		// 6. 执行上下移动
		if (stiffness > 0) {
			if (box.inAir) {
				mm.jumpModule.releaseJump();
			}
			mm.jumpModule.drop(ticker);
			box.velocityY += mm.jumpModule.jumpDy;
		} else if (climbing == NO_CLIMBING) {
			mm.jumpModule.drop(ticker);
			box.velocityY += mm.jumpModule.jumpDy;
		}
	}

	/**
	 * @param velocity 初始速度
	 * @param acceleration 加速度
	 * @param max 最大速度
	 */
	private void calcVelocity(float velocity, float acceleration, float max, Ticker ticker) {
		float dx = acceleration * ticker.duration;

		if (acceleration > 0) {
			pCurVx = Math.min(velocity + dx, max);
		} else { // (acceleration < 0)
			pCurVx = Math.max(velocity + dx, max);
		}
		deltaX = (velocity + pCurVx) * ticker.duration / 2;
	}

	/**
	 * 看看是否有空间供洛克滑铲, 即水平空间是否足够.
	 * 否则滑铲不会生效
	 * @return 是否可以生效滑铲. 返回 true 意味着已经转成滑铲状态
	 */
	private boolean trySlideStart() {
		Box box = mm;
		float anchorX = box.anchorX; // 原 x
		float anchorY = box.anchorY; // 原 y

		// 尝试进行状态转换
		String oldPattern = mm.currentPattern.name;
		mm.applyPattern(MegaMan.PATTERN_SLIDE);
		boolean success = mm.terrainHandler.glitchFix(box, true, true, false, false);
		if (!success) {
			mm.applyPattern(oldPattern);
			box.setAnchor(anchorX, anchorY);
			return false;
		}
		this.slideDuration = 0;
		return true;
	}

	/**
	 * <p>查看当滑铲结束时 / 或者起跳造成状态改变的, 能否恢复成普通状态.
	 * @return 返回 true 表示能够恢复, 但是未实现
	 */
	private boolean canSlideReset() {
		Box box = mm;
		float anchorX = box.anchorX;
		float anchorY = box.anchorY;

		// 尝试进行状态转换
		String oldPattern = mm.currentPattern.name;
		mm.applyPattern(PATTERN_NORMAL);
		boolean success = mm.terrainHandler.glitchFix(box, true, true, false, false);
		if (!success) {
			mm.applyPattern(oldPattern);
			box.setAnchor(anchorX, anchorY);
			return false;
		}

		slideDuration = -1;
		return true;
	}
}
